import BaseNode from "./BaseNode"

class RootMemory extends Map<string, any>{
  treeMemory: Map<string, TreeMemory> = new Map()
}

class TreeMemory extends Map<string, any>{
  nodeMemory: Map<string, NodeMemory> = new Map()
  constructor() {
    super()
    const nodes: BaseNode[] = []
    this.set('openNodes', nodes)
    this.set('traversalDepth', 0)
    this.set('traversalCycle', 0)
    this.set('nodeMemory', this.nodeMemory)
  }
}

class NodeMemory extends Map<string, any> {
  constructor() {
    super()
    const nodes: BaseNode[] = []
    this.set('openNodes', nodes)
    this.set('traversalDepth', 0)
    this.set('traversalCycle', 0)
  }
}

export default class Blackboard {

  _baseMemory: RootMemory
  _treeMemory: RootMemory

  constructor() {
    this._baseMemory = new RootMemory()
    this._treeMemory = new RootMemory()
  }

  _getTreeMemory(treeScope: string) {
    let memory = this._treeMemory.get(treeScope)
    if (!memory) {
      memory = new TreeMemory()
      this._treeMemory.set(treeScope, memory);
    }
    return memory;
  }

  _getNodeMemory(treeMemory: TreeMemory, nodeScope: string) {
    var memoryMap = treeMemory.nodeMemory;
    let nodeMemory = memoryMap.get(nodeScope)
    if (!nodeMemory) {
      nodeMemory = new NodeMemory()
      memoryMap.set(nodeScope, nodeMemory);
    }
    return nodeMemory;
  }

  _getMemory(treeScope: string | undefined, nodeScope: string | undefined): Map<string, any> {
    let memory: Map<string, any> = this._baseMemory;
    if (treeScope) {
      const tree = memory = this._getTreeMemory(treeScope);
      if (nodeScope) {
        memory = this._getNodeMemory(tree, nodeScope);
      }
    }
    return memory;
  }

  set(key: string, value: any, treeScope: string | undefined = undefined, nodeScope: string | undefined = undefined) {
    var memory = this._getMemory(treeScope, nodeScope);
    memory.set(key, value);
  }

  get(key: string, treeScope: string | undefined = undefined, nodeScope: string | undefined = undefined) {
    var memory = this._getMemory(treeScope, nodeScope);
    return memory.get(key);
  }
};
